Want to have a "perfect" ssl-labs score? An A+ 100/100/100/100 on SSLLabs that is? Here is my config file/example and adjust it for your own purposes. My last version was tls 1.2 only. This version allows for a non-compliant tls 1.3 implementation due to removal of all 128-bit ciphers for key-exchange. (hence the "perfect"...)
Code-snippets for Nginx with TLS1.3 and OpenSSL 1.1.1
# Configuration by Angelique Dawnbringer
# HTTPS server
server {
listen 1.2.3.4:443;
server_name example.net;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
server_tokens off;
ssl_certificate /etc/nginx/ssl/example.net/cert.crt;
ssl_certificate_key /etc/nginx/ssl/example.net/cert.key;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:2m;
ssl_session_timeout 5m;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp521r1:secp384r1;
# If you want to use 0-RTT uncomment the following line.
# However read https://tools.ietf.org/html/rfc8470 first.
#ssl_early_data on;
# Cipher Support-block
# Support for most browsers and systems but including some CBC-weak ciphers
# openssl ciphers 'EECDH+AESGCM:EDH+AESGCM:!DH:!RSA:!AES128'
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS_AES_256_GCM_SHA384:TLS-AES-256-GCM-SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA;
# Use this for non-CBC (no "weak" ciphers)
#ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS_AES_256_GCM_SHA384:TLS-AES-256-GCM-SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
# openssl ciphers 'EECDH+AESGCM:EDH+AESGCM:!DHE:!AES128'
#ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=31536000;";
# I am a big fan of ubiquitous encryption and HSTS ;) Go Preload! https://hstspreload.org/
#add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
resolver 8.8.8.8 8.8.4.4;
#Some document root#
}
The cipher blocks include issues with TLS1.3/NGINX version handling. I added the openssl code blocks above for you to filter those you want/need/are available. You can generate "cleaner" versions with these.
You could also take: ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
and remove AES128 and DHE versions.
TLS 1.3 specifics
Nginx and others do not support OpenSSL TLS1.3 cipher configuration. This has to do with RFC 8446. As of 1.1.1-c you can specify this and other settings in the openssl.cnf files. However, this does make you break the official mandatory cipher-list. The following ciphers are mandatory:
angelique@dawnbringer:/usr/local/src$ openssl ciphers -s -v | grep 1.3 TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
In our attempt to become 100/100/100/100, we will break compliance and configure OpenSSL to not use TLS_AES_128_GCM_SHA256
. In my use-cases, i tend to prioritize CHACHA20-poly1305 over AES for mobile support and such. In the past you needed to patch openssl and nginx for this. This is not the case anymore and you can very easily achieve this with the following block configuration change.
...
[default_conf]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT@SECLEVEL=2
Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
Options = ServerPreference,PrioritizeChaCha
...
This will state to your OS that the minimum TLS version used is TLS1.2 and the Ciphersuites to use ar the ones specified. Please note that I have only specified TLS1.3 suites. If you need
TLS1.2 support, do add "some" of them. You will now have a full 100/100/100/100 configuration using 256 bit encryption. (and a very strong key-exchange ;))
Examples or Stuck?
My website uses Cloudflare as a proxy and waf but scores lower than that. But all my internal hosts use this profile since I only want to use TLS1.2 or newer to begin with. This domain (oceandns) does have the above profile running: Check SSL Labs here. For an ECC/ECDSA enabled site check: here
Are you stuck on 90% key exchange? Then you most likely haven't changed or hard coded the SSL ECDH Curve setting. The standard value for Nginx is:
ssl_ecdh_curve prime256v1
Which will give you an equivalent of 3k instead of 4k. Change or set this value to:
ssl_ecdh_curve secp384r1;
Are you not able to get ECDSA to work? Then you most likely have not added an additional line and non-rsa -> ecc certificate to your configuration. For ECDSA to work, you need a ECC private key/and public key certificate.